<?php
/**
 * appRain v 0.1.x
 *
 * LICENSE
 *
 * This source file is subject to the MIT license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.opensource.org/licenses/mit-license.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@apprain.com so we can send you a copy immediately.
 *
 * @copyright  Copyright (c) 2010 appRain, Team. (http://www.apprain.com)
 * @license    http://www.opensource.org/licenses/mit-license.php MIT license
 *
 * HELP
 *
 * Official Website
 * http://www.apprain.com/
 *
 * Download Link
 * http://www.apprain.com/download
 *
 * Documents Link
 * http ://www.apprain.com/docs
 */

class appRain_Base_Modules_Universal_Installer extends appRain_Base_Objects
{
    const OVERWRITE = false;
    const SUPPORTED_EXT = 'zip';
    const UNIVERSAL_DEFANATION_FILE_NAME =  'installer.xml';
    const ADVANCED = 'advanced';
    const SIMPLE   = 'simple';
    
    public $errors = Array();
    
    private $mode  = 'auto';
    private $source_auto_delete = true;
    private $resourcepath = "";
    private $definationPath = "";
    private $defaultinstallationpath = "";
    private $tmp_path = null;
    private $xmlObj = Array();
    private $name = "";
    private $isAutoCopy = true;
 
    /* UPLOAD MANAGER */
    public function upload($fileRes)
    {
        if(!isset($this->tmp_path))$this->tmp_path = DATA;
        
        $resFileExt = App::Helper('Utility')->getExt($fileRes['name']);
        $resName = App::Helper('Utility')->getName($fileRes['name']);
        
        if($resFileExt != self::SUPPORTED_EXT) $this->errors[] = "File does not support";
        else if(file_exists($this->getDefaultinstallationpath() . DS . $resName))$this->errors[] = "'{$resName}' Component already installed";
        else if(!is_writable($this->tmp_path)) $this->errors[] = "Path is no writeable '{$this->tmp_path}'";
		else
        {
            $dirName = time();
            $this->tmp_path = $this->tmp_path . DS . $dirName;
            App::Helper('Utility')->createDir($this->tmp_path,0777);
            $fileInfo = App::Load("Helper/Utility")->upload($fileRes, $this->tmp_path . DS );
            $this->setResourcePath($this->tmp_path . DS . $fileInfo['file_name']);           
            $this->isAutoCopy = false;
        }
        
        return $this;
    }
    
    /* INSTALL RESOURCE
       =======================================================================*/
    public function Install()
    {
        if($this->prepare())
        {
            $this->temporary_extract()
                 ->checkDefinition()
                 ->executeCommand()
                 ->clearResource();
        }
        
        return $this;
    }
    
    private function prepare()
    {
        if(!empty($this->errors)) return false;
        
        if(!isset($this->tmp_path))$this->tmp_path = DATA;
        
        if(is_bool($this->getSourceAutoDelete())) $this->source_auto_delete = $this->getSourceAutoDelete();
        
        if($this->getResourcePath()) $this->resourcepath = $this->getResourcePath();
        if(!file_exists($this->resourcepath))
        {
            $this->errors[] = 'Source path not found: ' . $this->getResourcePath();
            return false;
        }
        
        $arr = preg_split('[\/|\\\|\.]',$this->resourcepath);
        $this->name = $arr[count($arr)-2];

        if($this->getDefaultInstallationPath()) $this->defaultinstallationpath = $this->getDefaultInstallationPath();
        if(!file_exists($this->defaultinstallationpath))
        {
            $this->errors[] = 'Default Installation path correct: ' . $this->getResourcePath();
            return false;
        }
        
        // Return Success
        return true;
    }
    
    private function temporary_extract()
    {
        if($this->isAutoCopy)
        {
            $dirName = time();
            $this->tmp_path = $this->tmp_path . DS . $dirName;
            App::Helper('Utility')->createDir($this->tmp_path,0777);
        }

        App::Module('Zip')
           ->setFileName($this->resourcepath)
           ->Extract($this->tmp_path);
        
        return $this;
    }
    
    private function checkDefinition($isResource=false)
    {
        if($isResource) $this->definationPath  = $this->resourcepath . DS . self::UNIVERSAL_DEFANATION_FILE_NAME;
        else $this->definationPath = $this->tmp_path . DS . $this->name . DS . self::UNIVERSAL_DEFANATION_FILE_NAME;
        
        if(!file_exists($this->definationPath))
        {
            $this->mode = self::SIMPLE;
        }
        else
        {
            $this->xmlObj = simplexml_load_file($this->definationPath);
            $this->mode = self::ADVANCED;    
        }

       return $this;
    }   
    
    private function executeCommand()
    {
        if($this->mode == self::SIMPLE)
        {
            App::Helper('Utility')->dirFullCopy($this->tmp_path . DS . $this->name,$this->defaultinstallationpath . DS . $this->name);
        }
        else
        {
            foreach($this->xmlObj->command->copy as $command)
            {
                $src = $this->senitizePath((string) $command->src);                
                $des = $this->senitizePath((string) $command->des,true);
                   
                if(!file_exists($des))
                {
                    App::Helper('Utility')->dirFullCopy($src,$des);
                }   
                else $this->errors[] = "Already exists : {$des}";    
            }
            
            $definition_path = $this->defaultinstallationpath . DS . $this->name . DS . self::UNIVERSAL_DEFANATION_FILE_NAME;
            
            if(file_exists($definition_path))$this->errors[] = "Already exists : {$definition_path}";
            else
            {
                App::Helper('Utility')->Copy($this->definationPath,$definition_path);
            }
        }
        
        return $this;
    }
    
    private function clearResource()
    {
        App::Helper('Utility')->dirFullRemove($this->tmp_path);
        
        if($this->source_auto_delete)
        {
            App::Helper('Utility')->deleteFile($this->resourcepath);
        }
        
    }
    
    private function senitizePath($src="",$isBase=false)
    {
       return ($isBase) ? App::Helper('Config')->rootDir($src) : $this->tmp_path . DS . $this->name . $src;
    }
    
    /* UNINSTALL RESOURCE
       =======================================================================*/
    public function Uninstall()
    {
        $this->resourcepath = $this->getResourcePath();
        $this->checkDefinition(true)
             ->Run();
    }
    
    public function Run()
    {
        if($this->mode == self::SIMPLE)
        {
            App::Helper('Utility')->dirFullCopy($this->resourcepath);
        }
        else
        {
            foreach($this->xmlObj->command->copy as $command)
            {
                $path = $this->senitizePath((string)$command->des,true);
                if(file_exists($path))
                {
                    App::Helper('Utility')->dirFullRemove($path);
                }   
            }
        }
    }
}